package cn.labbook.bluetooth.task;

import cn.labbook.bluetooth.constant.BillingVerificationConstant;
import cn.labbook.bluetooth.entity.*;
import cn.labbook.bluetooth.entity.wxpay.WXPay;
import cn.labbook.bluetooth.entity.wxpay.WxPayBillInfo;
import cn.labbook.bluetooth.entity.wxpay.WxPayBillResult;
import cn.labbook.bluetooth.service.*;
import cn.labbook.bluetooth.util.weixin.pay.PayUtil;
import cn.labbook.bluetooth.util.weixin.pay.UUIDHexGenerator;
import cn.labbook.bluetooth.util.weixin.pay.XmlUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import net.javacrumbs.shedlock.core.LockAssert;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.dom4j.DocumentException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
@Lazy(false)
public class AmmeterTask {

    @Autowired
    IAmmeterService ammeterService;
    @Autowired
    ITenantPayService tenantPayService;
    @Autowired
    IAdminService adminService;
    @Autowired
    IUserService userService;
    @Autowired
    private IConstantService constantService;
    @Autowired
    private ITransferRecordService transferRecordService;
    @Autowired
    private ITenantAmmeterPayViewService tenantAmmeterPayViewService;
    @Autowired
    private IBillingVerificationRecordService billingVerificationRecordService;
    @Autowired
    private IBillingVerificationRecordDetailService billingVerificationRecordDetailService;

    private final static String mch_id = "1491927112";
    private final static String key = "&key=zk123sqweqdsadZK9120392018490184";
    private final static String appid = "wxafeeae8c758d838d";


    public static void main(String[] args) throws DocumentException, InterruptedException {
        // billVerification();
    }

    // @Scheduled(cron = "0 0 11 * * ?")
    public void rePayment() throws Exception {
        log.info("--------------------------------定时转账开始--------------------------------");
        if (!constantService.timingTransferOpen()) {
            log.info("--------------------------------定时转账未开启--------------------------------");
            return;
        }


        LambdaQueryWrapper<TenantPay> lambda_1 = (new QueryWrapper()).lambda();
        lambda_1.eq(TenantPay::getPayStatus, 0);
        lambda_1.eq(TenantPay::getIsArrive, 1);
//        lambda_1.le(TenantPay::getManagerAmount, TenantPayConstant.MAX_AMOUNT);
        lambda_1.orderByAsc(TenantPay::getPayTime);

        List<TenantPay> tenantPays = this.tenantPayService.list(lambda_1);
        System.out.println(tenantPays);
        for (TenantPay tenantPay : tenantPays) {
            // 暂停两秒，防止微信转账凭证重复
            Thread.sleep(2000);
            transferRecordService.transfer(tenantPay);
        }
    }

    /**
     * 账单校验
     */
    @Scheduled(cron = "0 0 12 * * ?")
    @SchedulerLock(name = "billVerificationTask", lockAtMostFor = "5m")
    public void billVerification() {
        LockAssert.assertLocked();
        log.info("--------------------------------定时账单校验--------------------------------");

        /**
         * 微信的账单在次日 9:00 生成
         * 因此需要获取昨天的日期来获取账单
         */
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, -24);
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");

        // 构造基本信息
        WXPay wxPay = new WXPay();
        wxPay.setAppid(appid);
        wxPay.setBill_date(formatter.format(calendar.getTime()));
        wxPay.setBill_type("ALL");
        wxPay.setMch_id(mch_id);
        wxPay.setNonce_str(UUIDHexGenerator.generate());
        // wxPay.setTar_type("GZIP");

        // 构造参数
        Map<String, Object> sParaTemp = new HashMap<>();
        sParaTemp.put("appid", wxPay.getAppid());
        sParaTemp.put("bill_date", wxPay.getBill_date());
        sParaTemp.put("bill_type", wxPay.getBill_type());
        sParaTemp.put("mch_id", wxPay.getMch_id());
        sParaTemp.put("nonce_str", wxPay.getNonce_str());
        // sParaTemp.put("tar_type", wxPay.getTar_type());

        // 对请求参数进行签名
        Map sPara = PayUtil.paraFilter(sParaTemp);
        String prestr = PayUtil.createLinkString(sPara);
        String mysign = PayUtil.sign(prestr, key, "utf-8").toUpperCase();
        wxPay.setSign(mysign);

        // 使用设置好的请求参数请求下载账单接口，获得数据流
        String respXml = XmlUtil.messagePayToXML(wxPay);
        respXml = respXml.replace("__", "_");
        String param = respXml;
        String billResult = PayUtil.ssl("https://api.mch.weixin.qq.com/pay/downloadbill", param);

        log.info("------------------------账单数据流下载成功，开始进行数据解析------------------------");

        // 解析下载账单获取的数据流 ，方法拷贝自 https://github.com/Wechat-Group/WxJava
        WxPayBillResult wxPayBillResult = WxPayBillResult.fromRawBillResultString(billResult);

        // 添加当天的账单校验记录
        BillingVerificationRecord billingVerificationRecord = new BillingVerificationRecord();
        BeanUtils.copyProperties(wxPayBillResult, billingVerificationRecord);

        billingVerificationRecord.setBillingDate(calendar.getTime());
        billingVerificationRecordService.save(billingVerificationRecord);

        log.info("------------------------账单数据流解析成功，异步进行账单校验------------------------");

        // 使用异步做详细的比对
        new Thread(() -> {
            // 获取账单详细列表
            List<WxPayBillInfo> billInfoList = wxPayBillResult.getBillInfoList();
            List<String> outTradeNoList = billInfoList.stream().map(WxPayBillInfo::getOutTradeNo).collect(Collectors.toList());

            LambdaQueryWrapper<TenantAmmeterPayView> lambda = new LambdaQueryWrapper<>();
            lambda.in(TenantAmmeterPayView::getTenantPayId, outTradeNoList);

            // 直接根据账单详细列表中的商户订单号查询完整的支付记录
            List<TenantAmmeterPayView> tenantAmmeterPayViews = tenantAmmeterPayViewService.list(lambda);

            // 校验正确与错误统计
            int correctCount = 0;
            int errorCount = 0;

            for (WxPayBillInfo billInfo : billInfoList) {

                String outTradeNo = billInfo.getOutTradeNo();
                String totalAmount = billInfo.getTotalAmount();
                double totalAmountValue = Double.parseDouble(billInfo.getTotalAmount());

                Optional<TenantAmmeterPayView> optionalTenantAmmeterPayView = tenantAmmeterPayViews.stream()
                        .filter(tenantAmmeterPayView -> tenantAmmeterPayView.getTenantPayId().equals(outTradeNo))
                        .findAny();

                BillingVerificationRecordDetail billingVerificationRecordDetail = new BillingVerificationRecordDetail();
                billingVerificationRecordDetail.setBillingVerificationRecordId(billingVerificationRecord.getId());
                billingVerificationRecordDetail.setTotalAmount(totalAmount);

                Double payAmount = optionalTenantAmmeterPayView.orElseGet(TenantAmmeterPayView::new).getPayAmouont();
                String tenantPayId = optionalTenantAmmeterPayView.orElseGet(TenantAmmeterPayView::new).getTenantPayId();
                billingVerificationRecordDetail.setPayAmount(payAmount);
                billingVerificationRecordDetail.setTenantPayId(tenantPayId);

                // 对比金额
                if (totalAmountValue == payAmount) {
                    correctCount++;
                    billingVerificationRecordDetail.setVerificationResult(BillingVerificationConstant.BILLING_VERIFICATION_CORRECT);
                } else {
                    errorCount++;
                    billingVerificationRecordDetail.setVerificationResult(BillingVerificationConstant.BILLING_VERIFICATION_ERROR);
                }

                // 保存账单校验详情
                billingVerificationRecordDetailService.save(billingVerificationRecordDetail);
            }

            // 更新账单校验记录
            billingVerificationRecord.setCorrectCount(correctCount);
            billingVerificationRecord.setErrorCount(errorCount);
            billingVerificationRecordService.saveOrUpdate(billingVerificationRecord);

            log.info("-------------------------------账单校验完成-------------------------------");
        }, ("Thread-Verification")).start();
    }

    /* @Scheduled(cron = "0 25 15 * * ? ")
    public void taskTest(){
        log.info("----------------定时任务测试----------------");
    } */


    public double getNowPrice(String ammeterId) {
        LambdaQueryWrapper<Ammeter> lambda1 = (new QueryWrapper()).lambda();
        lambda1.eq(Ammeter::getAmmeterId, ammeterId);
        Ammeter one = this.ammeterService.getOne(lambda1);
        LambdaQueryWrapper<Admin> lambda2 = (new QueryWrapper()).lambda();
        lambda2.eq(Admin::getAdminId, one.getAdminId());
        Admin one1 = this.adminService.getOne(lambda2);
        return one1.getPayRate();
    }


//    @Autowired
//    IAmmeterService ammeterService;
    // 到期时间比较当前时间 如果到期变更电表服务状态为已欠费
//    @Scheduled(cron = "0 */5 * * * ?")
//    public void ammeterTime(){
//        LambdaQueryWrapper<Ammeter> lambda = new QueryWrapper().lambda();
//        lambda.le(Ammeter::getServerTime,new Date());
//        List<Ammeter> list = ammeterService.list(lambda);
//        list.forEach(ammeter -> {
//            if(ammeter.getServerTime().compareTo(new Date())<=0){
//                ammeter.setServerStatus(AmmeterConstant.serverStatus.EXPIRE);
//                if(ammeter.getSwitchStatus()==AmmeterConstant.switchStatus.YES){
//                    ammeter.setValve(AmmeterConstant.valve.OFF);
//                }
//                ammeterService.updateById(ammeter);
//            }
//        });
//
//    }


    // 到期时间是否在30天之内 在就变为即将到期
//    @Scheduled(cron = "0 */5 * * * ?")
//    public void reminder() throws Exception{
//        LambdaQueryWrapper<Ammeter> lambda = new QueryWrapper().lambda();
//        lambda.eq(Ammeter::getServerStatus,AmmeterConstant.serverStatus.NOTEXPIRE);
//        lambda.le(Ammeter::getServerTime, TimeUtils.addDate(30));
//        List<Ammeter> list = ammeterService.list(lambda);
//        list.forEach(ammeter -> {
//                ammeter.setServerStatus(AmmeterConstant.serverStatus.UPCOMINGEXPIRE);
//                ammeterService.updateById(ammeter);
//        });
//    }
}

